package com.gengzp.permission.config;

import com.gengzp.permission.tools.PermissionEnvironmentVariableReader;
import io.lettuce.core.*;
import io.lettuce.core.resource.ClientResources;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.time.Duration;

import static com.gengzp.permission.constants.PermissionBeanNameConstants.PERMISSION_ENVIRONMENT_VARIABLE_READER;

/**
 * @ClassName PermissionRedisConfig
 * @Description 优化版权限认证框架Redis配置类
 * @Author gengzp
 * @Date 2025/8/14 0:32
 */
@Configuration
@DependsOn(PERMISSION_ENVIRONMENT_VARIABLE_READER)
public class PermissionRedisConfig {

    private static final Logger logger = LoggerFactory.getLogger(PermissionRedisConfig.class);

    /**
     * 权限专用redis连接工厂配置，优化连接池和超时设置
     */
    @Bean
    public RedisConnectionFactory permissionRedisConnectionFactory() {
        // 创建 Redis 单实例配置
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(
                PermissionEnvironmentVariableReader.getRedisHost(),
                PermissionEnvironmentVariableReader.getRedisPort());
        config.setPassword(PermissionEnvironmentVariableReader.getRedisPassword());
        config.setDatabase(PermissionEnvironmentVariableReader.getRedisDatabase());

        // 优化的Socket选项
        SocketOptions socketOptions = SocketOptions.builder()
                .connectTimeout(Duration.ofSeconds(10)) // 增加连接超时时间
                .keepAlive(true) // 启用TCP keepalive，保持连接活跃
                .build();

        // 优化的客户端选项
        ClientOptions clientOptions = ClientOptions.builder()
                .socketOptions(socketOptions)
                .autoReconnect(true) // 启用自动重连
                .pingBeforeActivateConnection(true) // 激活前ping检测
                .timeoutOptions(TimeoutOptions.builder()
                        .fixedTimeout(Duration.ofSeconds(15)) // 增加固定超时时间
                        .build())
                .build();

        // 优化的连接池配置（针对权限校验场景）
        GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
        poolConfig.setMaxTotal(128); // 降低最大连接数，避免连接过多
        poolConfig.setMaxIdle(32);   // 降低最大空闲连接
        poolConfig.setMinIdle(16);   // 设置最小空闲连接，保证基本可用性
        poolConfig.setMaxWait(Duration.ofMillis(5000)); // 连接池等待时间
        poolConfig.setTestOnBorrow(true); // 获取连接时测试有效性
        poolConfig.setTestWhileIdle(true); // 空闲时测试连接有效性
        poolConfig.setTimeBetweenEvictionRuns(Duration.ofMillis(30000)); // 30秒检测一次
        poolConfig.setMinEvictableIdleTime(Duration.ofMillis(60000)); // 1分钟最小空闲时间
        poolConfig.setNumTestsPerEvictionRun(3); // 每次检测3个连接
        poolConfig.setBlockWhenExhausted(true); // 连接池耗尽时阻塞等待
        poolConfig.setLifo(false); // LIFO可能导致连接老化问题

        // 创建客户端资源配置
        ClientResources clientResources = ClientResources.builder()
                .ioThreadPoolSize(4) // 为权限校验场景优化线程池
                .computationThreadPoolSize(4)
                .build();

        // 创建 Lettuce 连接池配置
        LettucePoolingClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                .clientOptions(clientOptions)
                .clientResources(clientResources)
                .poolConfig(poolConfig)
                .commandTimeout(Duration.ofSeconds(15)) // 命令超时时间
                .build();

        // 创建并返回 Lettuce 连接工厂
        LettuceConnectionFactory factory = new LettuceConnectionFactory(config, clientConfig);
        factory.afterPropertiesSet(); // 确保配置生效
        return factory;
    }

    /**
     * 自定义权限专用redis模板，优化序列化配置
     */
    @Bean
    public RedisTemplate<String, Object> permissionRedisTemplate(RedisConnectionFactory permissionRedisConnectionFactory) {
        // 创建RedisTemplate对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置连接工厂
        template.setConnectionFactory(permissionRedisConnectionFactory);

        // 创建json序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // 设置key的序列化为String
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // 设置value的序列化
        template.setValueSerializer(jsonRedisSerializer);
        template.setHashValueSerializer(jsonRedisSerializer);

        template.afterPropertiesSet();
        return template;
    }
}



